#include "fileclient.h"
#include "ui_fileclient.h"

#include <QTcpSocket>
#include <QFileInfo>
#include <QFileDialog>
#include <QThread>

fileclient::fileclient(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::fileclient)
{
    ui->setupUi(this);
    m_tcpServer = new QTcpServer(this);
}

fileclient::~fileclient()
{
    delete ui;
}

bool fileclient::startServer()
{
    if(!checkFile(ui->fileEdit->text())) {
        return false;
    }
    m_tcpServer->listen(QHostAddress::Any, 8888);
    connect(m_tcpServer, &QTcpServer::newConnection, this, &fileclient::delNewConnect);
    return true;
}

void fileclient::delNewConnect()
{
    QTcpSocket* socket = m_tcpServer->nextPendingConnection();
    connect(socket, &QTcpSocket::readyRead, [=]() {
        dealMsg(socket);
    });
}

void fileclient::dealMsg(QTcpSocket *socket) // 处理客户端发送过来的文件信息和数据
{
    QDataStream in(socket);
    int typeMsg;
    in >> typeMsg;
    qDebug() << QString("收到客户端发来的消息：%1").arg(typeMsg);
    if(typeMsg == MsgType::FileInfo) {
        // 发送文件信息
        transferFileInfo(socket);
    }
    else if(typeMsg == MsgType::FileData) {
        // 发送文件数据
        transferFileData(socket);
    }
}

void fileclient::transferFileData(QTcpSocket *socket) // 发送文件的具体信息
{
    qint64 payloadSize = 1024*m_speed; //每一帧发送1024*64个字节，控制每次读取文件的大小，从而传输速度

    double progressByte= 0;//发送进度
    qint64 bytesWritten=0;//已经发送的字节数

    while(bytesWritten != m_sendFileSize) {
        int progress = static_cast<int>(bytesWritten/1.0/m_sendFileSize*100); // 进度条
        if(bytesWritten<m_sendFileSize){

            QByteArray DataInfoBlock = m_localFile.read(qMin(m_sendFileSize,payloadSize));

            qint64 WriteBolockSize = socket->write(DataInfoBlock, DataInfoBlock.size());

            QThread::usleep(3); //添加延时，防止服务端发送文件帧过快，否则发送过快，客户端接收不过来，导致丢包
            //等待发送完成，才能继续下次发送，
            if(!socket->waitForBytesWritten(3*1000)) {
//                ui->textBrowser->append("网络请求超时");
                qDebug() << "网络请求超时";
                return;
            }
            bytesWritten += WriteBolockSize;
            ui->sendProgressBar->setValue(progress);
        }
        if(bytesWritten==m_sendFileSize){
            qDebug() << QString("当前上传进度：%1/%2 -> %3%").arg(bytesWritten).arg(m_sendFileSize).arg(progress);
            qDebug() << QString("-------------对[%1]的文件传输完成！------------------").arg(socket->peerAddress().toString());
            ui->sendProgressBar->setValue(100);
            m_localFile.close();
            return;
        }
        if(bytesWritten > m_sendFileSize) {
            qDebug() << "意外情况！！！";
            return;
        }
        if(bytesWritten/1.0/m_sendFileSize > progressByte) {
            qDebug() << QString("当前上传进度：%1/%2 -> %3%").arg(bytesWritten).arg(m_sendFileSize).arg(progress);
            progressByte+=0.1;
        }

    }

}

void fileclient::transferFileInfo(QTcpSocket *socket) // 发送文件信息
{
    //获取文件数据，准备发送
    QByteArray  DataInfoBlock = getFileContent(ui->fileEdit->text());

    QThread::msleep(10); //添加延时
    m_fileInfoWriteBytes = socket->write(DataInfoBlock) - typeMsgSize;
    qDebug()<< "传输文件信息，大小："<< m_sendFileSize;

    //等待发送完成，才能继续下次发送，否则发送过快，对方无法接收
    if(!socket->waitForBytesWritten(10*1000)) { // 这个if直接就是传输了，如果没传输成功就报错，结束
        qDebug() << QString("网络请求超时,原因：%1").arg(socket->errorString());
        return;
    }

    qDebug() << QString("文件信息发送完成，开始对[%1]进行文件传输") .arg(socket->localAddress().toString());

    qDebug()<<"当前文件传输线程id:"<<QThread::currentThreadId();

    m_localFile.setFileName(m_sendFilePath);

    if(!m_localFile.open(QFile::ReadOnly)){ // 如果使用只读的方式打开都不行的话，就打开失败了
        qDebug()<<QString("文件[%1]打开失败！").arg(m_sendFilePath);
        return;
    }
}

QByteArray fileclient::getFileContent(QString filePath) // 获取文件的信息
{
    if (!QFile::exists(filePath)) { // 如果没有选中文件
        qDebug() <<QString("请选择你要发送的文件" + filePath);
        return "";
    }
    m_sendFilePath = filePath;
    qDebug() << QString("正在获取文件信息，文件路径是：[%1]......").arg(filePath);
    QFileInfo info(filePath);

    //获取要发送的文件大小
    m_sendFileSize = info.size();
    qDebug() << QString("要发送的文件大小：%1字节，%2M").arg(m_sendFileSize).arg(m_sendFileSize/1024/1024.0);

    //获取发送的文件名
    QString currentFileName=filePath.right(filePath.size()-filePath.lastIndexOf('/')-1);
    QByteArray DataInfoBlock;

    // 定义了数据传输流版本,并将下面的数据流放进了QByteArray类型里，方便后续接收端恢复
    QDataStream sendOut(&DataInfoBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_12);

    int type = MsgType::FileInfo; // 这里是枚举了消息的类型

    //封装发送的信息到DataInfoBlock中
        //消息类型             文件名                  //文件大小
    sendOut<<int(type)<<QString(currentFileName)<<qint64(m_sendFileSize);

//    ui->textBrowser->append(QString("文件[%1]信息获取完成！").arg(currentFileName));
    qDebug() << QString("文件[%1]信息获取完成！").arg(currentFileName);

    //发送的文件总大小中，信息类型不计入
    QString msg;
    if (m_sendFileSize>1024*1024) {
        msg = QString("%1M").arg(m_sendFileSize/1024/1024.0);
    }
    else {
        msg = QString("%1KB").arg(m_sendFileSize/1024.0);
    }
//    ui->textBrowser->append(QString("发送的文件名：%1，文件大小：%2").arg(currentFileName).arg(msg));
    qDebug() << QString("发送的文件名：%1，文件大小：%2").arg(currentFileName).arg(msg);

    return DataInfoBlock;
}

bool fileclient::checkFile(QString filePath) // 检查是否选择了待传输的文件
{
    QFile file(filePath);
    if(!file.exists(filePath)){
        qDebug() << "上传文件不存在！";
//        ui->textBrowser->append("上传文件不存在！");
        return false;
    }
    if(file.size()==0) {
        qDebug() << "上传文件为空文件！";
//        ui->textBrowser->append("上传文件为空文件！");
        return false;
    }
    return true;
}

////////////////////////////////////////

void fileclient::on_selectFilebtn_clicked() // 选择文件按钮
{
    qDebug()<< "selectFilebtn";
    QString filePath = QFileDialog::getOpenFileName(this, "选择文件", "./");
    if(filePath=="") return;
    ui->fileEdit->setText(filePath);
    QFile file(filePath);
    QString msg;
    if(file.size()>1024*1024) {
        msg = QString("大小：%1M").arg(file.size()/1024/1024.0);
    }
    else {
        msg = QString("大小：%1KB").arg(file.size()/1024.0);
    }
    ui->fileSizeLabel->setText(msg);
}

void fileclient::on_Serverbtn_clicked() // 发送文件按钮触发
{
    qDebug()<< "Serverbtn";
    if(ui->Serverbtn->text() == "发送文件") {
        // 这里同时包含了启动服务的函数，启动服务事实上就是服务端选好了文件，同时对设置中的端口开始了监听,同时建立了成功连接后触发的槽函数
        // 这个槽函数就是处理新的连接，处理新的连接函数里放建立了读取完socket后处理socket信息的函数
        if(!startServer())
        {
            return;
        }
        ui->Serverbtn->setText("取消发送");
    }
    else if(ui->Serverbtn->text() == "取消发送") {
        m_tcpServer->close();
        ui->Serverbtn->setText("发送文件");
    }
}

void fileclient::on_resetProgress_clicked() // 重置按钮触发
{
    ui->sendProgressBar->setValue(0);
    qDebug()<< "resetProgress";
}
